<template>
	<view class="fy-tree-select" @touchmove.stop.prevent="()=>{}">
		<!-- 用户自定义输入内容 -->
        <view @click.stop.prevent="handlerOpenModal"><slot></slot></view>

	    <uni-transition :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="visible" @click="handlerMaskClick" />
		<uni-transition :mode-class="['slide-bottom']" :styles="transClass" :duration="duration" :show="visible">
			<view class="fy-tree-select_wrapper" @touchmove.stop.prevent="()=>{}">
				<view class="fy-tree-select_bar" :style="customBarStyle" v-if="showBar">
                    <template v-if="$slots.bar">
                        <slot name="bar"></slot>
                    </template>
                    <template v-else>
                        <text class="fy-tree-select_bar__btn" :style="{color: cancelColor}" @click.stop.prevent="handlerCloseModal">{{ cancelText }}</text>
                        <text class="fy-tree-select_bar__btn" :style="{color: confirmColor}" @click.stop.prevent="handlerConfirm">{{ confirmText }}</text>
                    </template>
                </view>

				<view class="fy-tree-select_container" :style="{'height': `${height}px`}">
					<template v-for="(column, columnIndex) in treeList">
						<scroll-view :scroll-y="true" :key="columnIndex" :ref="`fy-tree-select_column_${columnIndex}`"
							:class="['fy-tree-select_column', `fy-tree-select_column_${columnIndex}`]"
							:style="{'height': `${height}px`}"
						>
							<template v-for="(item, index) in column">
								<view
									v-if="treePosition[columnIndex]" :class="['fy-tree-select_item']" :key="index"
									@click.stop.prevent="onChange(columnIndex, index)"
								>
									<text
										:style="{
											'height': `${itemHeight}px`,
											'line-height': `${itemHeight}px`,
											'font-size': `${fontSize}rpx`,
											'color': index == treePosition[columnIndex]['index'] ? activeColor : color
										}"
										class="fy-tree-select_item_text"
									>{{ item[label] }}</text>
								</view>
							</template>
							<view class="fy-tree-select_item" :style="{height: `${itemHeight}px`, 'border-top-width': '0px'}"></view>
						</scroll-view>
					</template>
				</view>
			</view>
		</uni-transition>
	  </view>
</template>

<script>
export default {
	name: "FyTreeSelect",
	props: {
		value: { type: Array, default() { return [] } }, // 默认值
		columns: { type: Number, default: 3 }, // 展示数据的列数, 可取值 1, 2, 3, 5

		closeOnClickMask: { type: Boolean, default: true }, // 点击遮罩是否关闭菜单

		showBar: { type: Boolean, default: true }, // 是否显示操作栏
        customBarStyle: { type: Object, default() { return {} } }, // 是否自定义操纵栏样式
		cancelText: { type: String, default: '取消' }, // 取消按钮文案
		confirmText: { type: String, default: '确定' }, // 确认按钮文案
		cancelColor: { type: String, default: '#666666' }, // 取消按钮颜色
		confirmColor: { type: String, default: '#4cd964' }, // 确定按钮颜色

		options: { type: Array, default() { return [] } }, // 展示数据
		height: { type: Number, default: 300 }, // 滚动列表的高度，超出将滚动显示
		itemHeight: { type: Number, default: 43 }, // 每个的高度 单位px
		duration:  { type: Number, default: 300 },

		children: { type: String, default: 'children' }, // 指定子树为节点对象的某个属性值
		label: { type: String, default: 'name' }, // 指定节点标签为节点对象的某个属性值
		primary: { type: String, default: 'id' }, // 指定节点唯一标识为节点对象的某个属性值
		optionsKey: { type: String, default: 'id' }, // 指定选中值位节点对象的某个属性值

		customChild: { type: Boolean, default: false }, // 是否是自定义子栏目更新

		fontSize: { type: Number, default: 30 }, // 字体大小，单位rpx
		color: { type: String, default: '#3F3F3F' }, // 每项字体颜色
		activeColor: { type: String, default: '#4cd964' }, // 选中的每项字体颜色
	},
	data() {
		return {
			maskClass: { // 遮罩层样式
                'position': 'fixed', 'bottom': 0, 'top': 0, 'left': 0, 'right': 0, 'backgroundColor': 'rgba(0, 0, 0, 0.6)', 'z-index': '999999',
            },
            transClass: { // 内容弹框样式
                'position': 'fixed', 'left': 0, 'right': 0, 'bottom': 0, 'z-index': '999999',
            },

			visible: false,
			treeList: [], // 列表数据
			treePosition: [],
		}
	},
	watch: {
		visible: {
			immediate: true,
			handler: function(val) {
				if (val && this.treeList.length === 0) {
					this.updateData(this.options)
				}
			}
		}
	},
	created() {
		this.init();
	},
	methods: {
		// 初始化处理数据展示
		init() {
			try {
				const columns = this.columns;
				let index = 0;
				while (index < columns) {
					if (index === columns-1) {
						this.$set(this.treePosition, index, { index: -1 });
					} else {
						this.$set(this.treePosition, index, { index: 0 });
					}
					index += 1;
				}
			} catch(err) {
				console.log(err)
			}
		},
		// 组装更新数据
		updateData(data) {
			try {
				const tempArray = [];
				let options = this.toJSON(data);

				if (options.length === 0) {
					return this.treeList = [];
				}

				for (let i = 0; i < this.columns; i++) {
					if (i === 0) {
						tempArray[0] = options;
					} else if (this.treePosition[i-1]) {
						tempArray[i] = this.getColumnData({ data: tempArray[i-1], index: this.treePosition[i-1]['index'] })
					}
				}

				this.treeList = this.toJSON(tempArray);

				if (Array.isArray(this.value) && this.value.length > 0) {
					this.setDefaultData();
				}
			} catch(err) {
				console.log(err);
			}
		},
		/**
		 * 组件默认值(初始化从父组件传进来的)
		*/
		setDefaultData() {
			try {
				const { treeList, value, columns, optionsKey } = this;

				for (let i = 0; i < columns; i++) {
					const columnList = treeList[i];
					if (!columnList || !Array.isArray(columnList) || columnList.length === 0) break;

					const len = columnList.length;

					if (value[i] !== 0 && !value[i]) {
						break;
					}

					for (let k = 0; k < len; k++) {
						const item = columnList[k];
						if (item[optionsKey] == value[i]) {
							this.$set(this.treePosition, i, { index: k }); break;
						}
					}
				}
			} catch(err) {
				console.log(err);
			}
		},

		/**
		 * @param {number} column - 代表的列数(0, 1, 2);
		 * @param {number} index - 当前列表，滚动到的行数索引
		 */
		onChange(column, index) {
			try {
				const currentColumn = this.treeList[column]; // 当前列的数据
				const oldItem = currentColumn[this.treePosition[column].index]; // 存储列的数据
				const colLen = this.treeList.length; // 旧数据的长度

				if (index === this.treePosition[column].index && !this.customChild) return;
				this.setPosAttr(column, 'index', index); // 更新选中列的下标

				const newItem = currentColumn[index];
				
				const resultData = { current: this.toJSON(newItem), prev: this.toJSON(oldItem), column, index };
				const SelectData = this.getColumnSelectData() || {};
				this.$emit('change', Object.assign({}, resultData, SelectData))

				if (this.customChild === true) { // 自定义更新
					return;
				}

				// 依次更新后面列的数据
				for (let i = column+1; i < this.columns; i++) {
					this.resetColumn(i);
					this.$set(this.treeList, i, this.getColumnData({ data: this.treeList[i-1], index: this.treePosition[i - 1].index }))
				}
			} catch(err) { console.log(err) }
		},
		/**
		 * 提取每列选中的数据
		*/
		getColumnSelectData() {
			try {
				const data = this.treeList;
				const columns = data.length;
				const treePosition = this.treePosition;
				const selected = [];

				let index = 0;
				while (index < columns) {
					if (treePosition[index]['index'] > -1) {
						const item = data[index][treePosition[index]['index']];
						selected.push(item);
					} else {
						selected.push(null);
					}
					index += 1;
				}

				return { selected: JSON.parse(JSON.stringify(selected)) };
			} catch(err) {
				console.log(err)
			}
		},
		/**
		 * 更新指定列的数据（供外部调用）
		 * @param { Array } data 更新的数据
		 * @param { Number } columnIndex 更新的列
		*/
		updateColumnData(data = [], columnIndex = 0) {
			try {
				this.treeList.splice(columnIndex, 1, this.toJSON(data));
				this.resetColumn(columnIndex);
				// 依次更新后面列的数据
				for (let i = columnIndex+1; i < this.columns; i++) {
					this.resetColumn(i);
					this.$set(this.treeList, i, this.getColumnData({ data: this.treeList[i-1], index: this.treePosition[i-1].index }))
				}
			} catch(err) {
				console.log(err);
			}
		},
		/**
		 * 获取列的数据
		 * @param { Array } data
		 * @param {number} index - 当前的列表下标
		*/
		getColumnData({ data, index }) {
			try {
				return data[index] ? data[index][this.children] || [] : [];
			} catch(err) {
				console.log(err);
			}
		},
		/**
		 * @param {number} column - 当前的列数
		 **/
		resetColumn(column) {
			this.$set(this.treePosition, column, { index: column == this.columns - 1 ? -1 : 0 });
		},
		/**
		 * 深度拷贝对象
		*/
		toJSON(data) {
			if (typeof data === 'object') {
				return JSON.parse(JSON.stringify(data));
			} else {
				return {}
			}
		},
		/**
		 * 更新选中列的下标
		 * @param { Number } index // 第几列
		 * @param { String } attr // 列的属性
		 * @param { any } val // 属性值
		*/
		setPosAttr(index, attr, val) {
			try {
				this.$set(this.treePosition[index], attr, val)
			} catch(err) {
				console.log(err);
			}
		},
		/**
		 * 点击确认按钮
		*/
		handlerConfirm() {
			try {
				const data = this.treeList;
				const columns = this.columns;
				const treePosition = this.treePosition;
				const selected = [];

				let index = 0;
				let values = [];
				let primary = [];
				while (index < columns) {
					const curPosition = treePosition[index];
					const item = data[index][curPosition.index] || {};
					values.push(item[this.optionsKey]);
					primary.push(item[this.primary]);
					selected.push(item || null);
					index += 1;
				}

				this.$emit('confirm', { primary, values, selected: this.toJSON(selected) })
				this.$emit('input', values)
				this.handlerCloseModal();
			} catch(err) {
				console.log(err);
			}
		},
		// 点击遮罩
		handlerMaskClick() {
			// 如果不允许点击遮罩，直接返回
			if (!this.closeOnClickMask) return;
			this.handlerCloseModal();
		},
		/**
		 * 隐藏模态框
		*/
		handlerCloseModal() {
			this.visible = false;
			this.$emit('close', { visible: false });
		},
		/**
		 * 显示模态框
		*/
		handlerOpenModal() {
			this.visible = true;
			this.$emit('open', { visible: true });
		},
	}
}
</script>

<style lang="scss">
@import './fy-tree-select.scss';
</style>
